//package com.geek.bams.server;
//
//import com.geek.bams.entity.Account;
//import com.geek.bams.exception.*;
//import com.geek.bams.service.Bank;
//
//import java.io.BufferedReader;
//import java.io.IOException;
//import java.io.InputStreamReader;
//import java.io.ObjectOutputStream;
//import java.net.Socket;
//import java.net.SocketException;
//
///**
// *
// * ServerTasker  "银行业务员"
// *   1.读取客户端发送来的指令            BufferedReader
// *   2.解析指令，根据指令来执行Bank业务   Bank
// *   3.写回执行的结果 （成功则返回Account账户信息，失败则返回String异常信息） ObjectOutputStream
// */
///**
// * ServerTasker "业务员"
// * 1.读取ATMClient客户端发送的指令  login#862150212025100001#123
// * 2.解析指令，发起对Bank业务的调用
// * 3.写回业务执行的结果 （业务执行成功返回Account，业务执行失败返回异常信息String）
// */
//public class ServerTasker implements Runnable{
//
//    Bank bank;
//    Socket socket;
//
//    public ServerTasker(Bank bank , Socket socket){
//        this.bank = bank;
//        this.socket = socket;
//    }
//
//    @Override
//    public void run() {
//        try (
//                //读指令
//                BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//                //写结果
//                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//        ){
//            String line = null;
//            Account acc = null;
//
//            //2.读取客户端发送的指令
//            while ((line = br.readLine())!=null){
//                //login#862150212025100001#123  指令
//                System.out.println("指令 line = "+line);
//                //解析指令
//                String[] splits = line.split("#");
//                switch (splits[0]){
//                    case "login":
//                        try {
//                            //执行Bank的登录业务
//                            acc = bank.login(Long.valueOf(splits[1]) , splits[2]);
//                            if(acc!=null){
//                                //3.写回执行登录成功的结果 - Account信息给客户端
//                                oos.writeObject(acc);
//                                oos.flush();
//                            }
//                        } catch (NumberFormatException e) {
//                            //3.写回执行登录失败的结果 - String异常信息给客户端
//                            oos.writeObject("登录账号信息不合法");
//                            oos.flush();
//                        } catch (LoginException e) {
//                            //3.写回执行登录失败的结果 - String异常信息给客户端
//                            oos.writeObject(e.getMessage());
//                            oos.flush();
//                        }
//                        break;
//                    case "register":
//                        try {
//                            int type = Integer.parseInt(splits[6]);
//                            acc = bank.register(splits[1], splits[2], splits[3], splits[4], splits[5], type);
//                            if(acc!=null){
//                                //3.写回执行注册成功的结果 - Account信息给客户端
//                                oos.writeObject(acc);
//                                oos.flush();
//                            }
//                        } catch (NumberFormatException e) {
//                            //3.写回执行注册失败的结果 - String异常信息给客户端
//                            oos.writeObject("账户类型信息不合法");
//                            oos.flush();
//                        } catch (NotFoundException | TypeException | RegisterException e) {
//                            //3.写回执行注册失败的结果 - String异常信息给客户端
//                            oos.writeObject(e.getMessage());
//                            oos.flush();
//                        }
//                        break;
//                    case "deposit":   //存款
//                        try {
//                            acc = bank.deposit(Long.valueOf(splits[1]), Double.parseDouble(splits[2]));
//                            if(acc!=null){
//                                //3.写回执行存款成功的结果 - Account信息给客户端
//                                oos.writeObject(acc);
//                                oos.flush();
//                            }
//                        } catch (NumberFormatException e) {
//                            //3.写回执行存款失败的结果 - String异常信息给客户端
//                            oos.writeObject("存款金额不合法");
//                            oos.flush();
//                        } catch (NotFoundException e) {
//                            //3.写回执行存款失败的结果 - String异常信息给客户端
//                            oos.writeObject(e.getMessage());
//                            oos.flush();
//                        }
//                        break;
//                    case "withdraw":   //取款
//                        try {
//                            acc = bank.withdraw(Long.valueOf(splits[1]), splits[2], Double.parseDouble(splits[3]));
//                            if(acc!=null){
//                                //3.写回执行取款成功的结果 - Account信息给客户端
//                                oos.writeObject(acc);
//                                oos.flush();
//                            }
//                        } catch (NumberFormatException e) {
//                            //3.写回执行取款失败的结果 - String异常信息给客户端
//                            oos.writeObject("取款金额不合法");
//                            oos.flush();
//                        } catch (NotFoundException | BalanceNotEnoughException e) {
//                            //3.写回执行取款失败的结果 - String异常信息给客户端
//                            oos.writeObject(e.getMessage());
//                            oos.flush();
//                        }
//                        break;
//                    case "transfer":   //转账
//                        try {
//                            boolean flag = bank.transfer(Long.valueOf(splits[1]) , splits[2] , Long.valueOf(splits[3]) , Double.parseDouble(splits[4]));
//                            if(flag){
//                                //3.写回执行转账成功的结果 - Account信息给客户端
//                                acc = bank.login(Long.valueOf(splits[1]) , splits[2]);
//                                if(acc!=null){
//                                    oos.writeObject(acc);
//                                    oos.flush();
//                                }
//                            }
//                        } catch (NumberFormatException e) {
//                            //3.写回执行登录失败的结果 - String异常信息给客户端
//                            oos.writeObject("账号信息不合法");
//                            oos.flush();
//                        } catch (NotFoundException  | BalanceNotEnoughException | LoginException e) {
//                            //3.写回执行登录失败的结果 - String异常信息给客户端
//                            oos.writeObject(e.getMessage());
//                            oos.flush();
//                        }
//                        break;
//                    case "updateCeiling":   //设置透支额度
//                        try {
//                            acc = bank.updateCeiling(Long.valueOf(splits[1]), splits[2], Double.parseDouble(splits[3]));
//                            if(acc!=null){
//                                //3.写回执行设置透支额度成功的结果 - Account信息给客户端
//                                oos.writeObject(acc);
//                                oos.flush();
//                            }
//                        } catch (NumberFormatException e) {
//                            //3.写回执行设置透支额度失败的结果 - String异常信息给客户端
//                            oos.writeObject("透支额度不合法");
//                            oos.flush();
//                        } catch (TypeException | NotFoundException e) {
//                            //3.写回执行设置透支额度失败的结果 - String异常信息给客户端
//                            oos.writeObject(e.getMessage());
//                            oos.flush();
//                        }
//                        break;
//                    case "requestLoan":   //贷款
//                        try {
//                            acc = bank.requestLoan(Long.valueOf(splits[1]), Double.parseDouble(splits[2]));
//                            if(acc!=null){
//                                //3.写回执行贷款成功的结果 - Account信息给客户端
//                                oos.writeObject(acc);
//                                oos.flush();
//                            }
//                        } catch (NumberFormatException e) {
//                            //3.写回执行贷款失败的结果 - String异常信息给客户端
//                            oos.writeObject("贷款金额不合法");
//                            oos.flush();
//                        } catch (TypeException | NotFoundException e) {
//                            //3.写回执行贷款失败的结果 - String异常信息给客户端
//                            oos.writeObject(e.getMessage());
//                            oos.flush();
//                        }
//                        break;
//                    case "payLoan":   //还贷
//                        try {
//                            acc = bank.payLoan(Long.valueOf(splits[1]), Double.parseDouble(splits[2]));
//                            if(acc!=null){
//                                //3.写回执行还贷成功的结果 - Account信息给客户端
//                                oos.writeObject(acc);
//                                oos.flush();
//                            }
//                        } catch (NumberFormatException e) {
//                            //3.写回执行还贷失败的结果 - String异常信息给客户端
//                            oos.writeObject("还款金额不合法");
//                            oos.flush();
//                        } catch (TypeException | NotFoundException e) {
//                            //3.写回执行还贷失败的结果 - String异常信息给客户端
//                            oos.writeObject(e.getMessage());
//                            oos.flush();
//                        }
//                        break;
//                    case "close":
//                        //为了避免客户端关闭时的阻塞 ， 关闭时给予空响应
//                        oos.writeObject("");
//                        oos.flush();
//                        break;
//                }
//            }
//
//        } catch (SocketException e) {
//
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }
//    }
//}


//添加转账后，转入账户、上帝视角排行榜，自动刷新功能

package com.geek.bams.server;

import com.geek.bams.entity.Account;
import com.geek.bams.exception.*;
import com.geek.bams.service.Bank;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 *
 * ServerTasker  "银行业务员"
 *   1.读取客户端发送来的指令            BufferedReader
 *   2.解析指令，根据指令来执行Bank业务   Bank
 *   3.写回执行的结果 （成功则返回Account账户信息，失败则返回String异常信息） ObjectOutputStream
 */
public class ServerTasker implements Runnable{

    static Bank bank;
    Socket socket;
    // 添加IP地址跟踪
    static ConcurrentHashMap<String, Long> ipLoginMap = new ConcurrentHashMap<>();
    static ConcurrentHashMap<Long, String> loginIpMap = new ConcurrentHashMap<>();
    // 添加在线客户端列表，用于实时刷新
    static CopyOnWriteArrayList<ServerTasker> onlineClients = new CopyOnWriteArrayList<>();
    String clientIP;
    Long currentAccountId = null;
    ObjectOutputStream oos;
    boolean isActive = true;

    public ServerTasker(Bank bank , Socket socket){
        this.bank = bank;
        this.socket = socket;
        this.clientIP = socket.getRemoteSocketAddress().toString().substring(1); // 去掉开头的 "/"
        // 只保留IP部分，去掉端口号
        int colonIndex = this.clientIP.lastIndexOf(':');
        if (colonIndex > 0) {
            this.clientIP = this.clientIP.substring(0, colonIndex);
        }
    }

    @Override
    public void run() {
        try (
                //读指令
                BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                //写结果
                ObjectOutputStream tempOos = new ObjectOutputStream(socket.getOutputStream());
        ){
            this.oos = tempOos;
            String line = null;
            Account acc = null;

            // 添加当前客户端到在线列表
            onlineClients.add(this);

            //2.读取客户端发送的指令
            while ((line = br.readLine())!=null && isActive){
                System.out.println("指令 line = "+line);
                //解析指令
                String[] splits = line.split("#");
                switch (splits[0]){
                    /*case "login":
                        try {
                            Long accountId = Long.valueOf(splits[1]);

                            // 检查IP是否已经登录了其他账号
                            Long existingAccount = ipLoginMap.get(clientIP);
                            if (existingAccount != null && !existingAccount.equals(accountId)) {
                                //3.写回登录失败的结果 - IP已登录其他账号
                                oos.writeObject("该IP已经登录了其他账号");
                                oos.flush();
                                break;
                            }

                            acc = bank.login(accountId , splits[2]);
                            if(acc!=null){
                                // 记录登录信息
                                currentAccountId = accountId;
                                ipLoginMap.put(clientIP, accountId);
                                loginIpMap.put(accountId, clientIP);

                                //3.写回执行登录成功的结果 - Account信息给客户端
                                oos.writeObject(acc);
                                oos.flush();
                            }
                        } catch (NumberFormatException e) {
                            //3.写回执行登录失败的结果 - String异常信息给客户端
                            oos.writeObject("登录账号信息不合法");
                            oos.flush();
                        } catch (LoginException e) {
                            //3.写回执行登录失败的结果 - String异常信息给客户端
                            oos.writeObject(e.getMessage());
                            oos.flush();
                        }
                        break;*/
                    case "login":
                        try {
                            Long accountId = Long.valueOf(splits[1]);

                            // 检查IP是否已经登录了其他账号
                            Long existingAccount = ipLoginMap.get(clientIP);
                            if (existingAccount != null && !existingAccount.equals(accountId)) {
                                //3.写回登录失败的结果 - IP已登录其他账号
                                synchronized (oos) {
                                    oos.writeObject("该IP已经登录了其他账号");
                                    oos.flush();
                                }
                                break;
                            }

                            acc = bank.login(accountId, splits[2]);
                            if(acc!=null){
                                // 记录登录信息
                                currentAccountId = accountId;
                                ipLoginMap.put(clientIP, accountId);
                                loginIpMap.put(accountId, clientIP);

                                //3.写回执行登录成功的结果 - Account信息给客户端
                                synchronized (oos) {
                                    oos.writeObject(acc);
                                    oos.flush();
                                }
                            }
                        } catch (NumberFormatException e) {
                            //3.写回执行登录失败的结果 - String异常信息给客户端
                            synchronized (oos) {
                                oos.writeObject("登录账号信息不合法");
                                oos.flush();
                            }
                        } catch (LoginException e) {
                            //3.写回执行登录失败的结果 - String异常信息给客户端
                            synchronized (oos) {
                                oos.writeObject(e.getMessage());
                                oos.flush();
                            }
                        }
                        break;
                    case "register":
                        try {
                            int type = Integer.parseInt(splits[6]);
                            acc = bank.register(splits[1], splits[2], splits[3], splits[4], splits[5], type);
                            if(acc!=null){
                                //3.写回执行注册成功的结果 - Account信息给客户端
                                oos.writeObject(acc);
                                oos.flush();
                            }
                        } catch (NumberFormatException e) {
                            //3.写回执行注册失败的结果 - String异常信息给客户端
                            oos.writeObject("账户类型信息不合法");
                            oos.flush();
                        } catch (NotFoundException | TypeException | RegisterException e) {
                            //3.写回执行注册失败的结果 - String异常信息给客户端
                            oos.writeObject(e.getMessage());
                            oos.flush();
                        }
                        break;
                    case "deposit":   //存款
                        try {
                            acc = bank.deposit(Long.valueOf(splits[1]), Double.parseDouble(splits[2]));
                            if(acc!=null){
                                //3.写回执行存款成功的结果 - Account信息给客户端
                                oos.writeObject(acc);
                                oos.flush();

                                // 通知所有相关客户端刷新
                                notifyRefresh(acc.getId());
                            }
                        } catch (NumberFormatException e) {
                            //3.写回执行存款失败的结果 - String异常信息给客户端
                            oos.writeObject("存款金额不合法");
                            oos.flush();
                        } catch (NotFoundException e) {
                            //3.写回执行存款失败的结果 - String异常信息给客户端
                            oos.writeObject(e.getMessage());
                            oos.flush();
                        }
                        break;
                    case "withdraw":   //取款
                        try {
                            acc = bank.withdraw(Long.valueOf(splits[1]), splits[2], Double.parseDouble(splits[3]));
                            if(acc!=null){
                                //3.写回执行取款成功的结果 - Account信息给客户端
                                oos.writeObject(acc);
                                oos.flush();

                                // 通知所有相关客户端刷新
                                notifyRefresh(acc.getId());
                            }
                        } catch (NumberFormatException e) {
                            //3.写回执行取款失败的结果 - String异常信息给客户端
                            oos.writeObject("取款金额不合法");
                            oos.flush();
                        } catch (NotFoundException | BalanceNotEnoughException e) {
                            //3.写回执行取款失败的结果 - String异常信息给客户端
                            oos.writeObject(e.getMessage());
                            oos.flush();
                        }
                        break;
                    case "transfer":   //转账
                        try {
                            Long fromId = Long.valueOf(splits[1]);
                            Long toId = Long.valueOf(splits[3]);
                            double money = Double.parseDouble(splits[4]);

                            boolean flag = bank.transfer(fromId, splits[2], toId, money);
                            if(flag){
                                //3.写回执行转账成功的结果 - Account信息给客户端
                                acc = bank.login(fromId, splits[2]);
                                if(acc!=null){
                                    oos.writeObject(acc);
                                    oos.flush();

                                    // 通知所有相关客户端刷新（转出账户和转入账户）
                                    notifyRefresh(fromId);
                                    notifyRefresh(toId);
                                }
                            }
                        } catch (NumberFormatException e) {
                            //3.写回执行登录失败的结果 - String异常信息给客户端
                            oos.writeObject("账号信息不合法");
                            oos.flush();
                        } catch (NotFoundException  | BalanceNotEnoughException | LoginException e) {
                            //3.写回执行登录失败的结果 - String异常信息给客户端
                            oos.writeObject(e.getMessage());
                            oos.flush();
                        }
                        break;
                    case "updateCeiling":   //设置透支额度
                        try {
                            acc = bank.updateCeiling(Long.valueOf(splits[1]), splits[2], Double.parseDouble(splits[3]));
                            if(acc!=null){
                                //3.写回执行设置透支额度成功的结果 - Account信息给客户端
                                oos.writeObject(acc);
                                oos.flush();

                                // 通知所有相关客户端刷新
                                notifyRefresh(acc.getId());
                            }
                        } catch (NumberFormatException e) {
                            //3.写回执行设置透支额度失败的结果 - String异常信息给客户端
                            oos.writeObject("透支额度不合法");
                            oos.flush();
                        } catch (TypeException | NotFoundException e) {
                            //3.写回执行设置透支额度失败的结果 - String异常信息给客户端
                            oos.writeObject(e.getMessage());
                            oos.flush();
                        }
                        break;
                    case "requestLoan":   //贷款
                        try {
                            acc = bank.requestLoan(Long.valueOf(splits[1]), Double.parseDouble(splits[2]));
                            if(acc!=null){
                                //3.写回执行贷款成功的结果 - Account信息给客户端
                                oos.writeObject(acc);
                                oos.flush();

                                // 通知所有相关客户端刷新
                                notifyRefresh(acc.getId());
                            }
                        } catch (NumberFormatException e) {
                            //3.写回执行贷款失败的结果 - String异常信息给客户端
                            oos.writeObject("贷款金额不合法");
                            oos.flush();
                        } catch (TypeException | NotFoundException e) {
                            //3.写回执行贷款失败的结果 - String异常信息给客户端
                            oos.writeObject(e.getMessage());
                            oos.flush();
                        }
                        break;
                    case "payLoan":   //还贷
                        try {
                            acc = bank.payLoan(Long.valueOf(splits[1]), Double.parseDouble(splits[2]));
                            if(acc!=null){
                                //3.写回执行还贷成功的结果 - Account信息给客户端
                                oos.writeObject(acc);
                                oos.flush();

                                // 通知所有相关客户端刷新
                                notifyRefresh(acc.getId());
                            }
                        } catch (NumberFormatException e) {
                            //3.写回执行还贷失败的结果 - String异常信息给客户端
                            oos.writeObject("还款金额不合法");
                            oos.flush();
                        } catch (TypeException | NotFoundException e) {
                            //3.写回执行还贷失败的结果 - String异常信息给客户端
                            oos.writeObject(e.getMessage());
                            oos.flush();
                        }
                        break;
                    case "close":
                        // 清理登录信息
                        cleanup();
                        //为了避免客户端关闭时的阻塞 ， 关闭时给予空响应
                        oos.writeObject("");
                        oos.flush();
                        isActive = false;
                        break;
                    case "refresh": // 客户端请求刷新
                        try {
                            Long refreshId = Long.valueOf(splits[1]);
                            Account refreshAcc = bank.login(refreshId, splits[2]);
                            if(refreshAcc != null) {
                                oos.writeObject(refreshAcc);
                                oos.flush();
                            }
                        } catch (Exception e) {
                            // 忽略刷新异常
                        }
                        break;
                }
            }

        } catch (SocketException e) {

        } catch (IOException e) {
            // 清理登录信息
            cleanup();
            throw new RuntimeException(e);
        } finally {
            // 确保在任何情况下都清理登录信息
            cleanup();
            try {
                if (socket != null && !socket.isClosed()) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 从在线客户端列表中移除
            onlineClients.remove(this);
        }
    }

    // 清理资源
    private void cleanup() {
        if (currentAccountId != null) {
            ipLoginMap.remove(clientIP);
            loginIpMap.remove(currentAccountId);
            currentAccountId = null;
        }
    }

    // 通知相关客户端刷新
    private void notifyRefresh(Long accountId) {
        // 创建当前在线客户端的副本以避免并发修改异常
        CopyOnWriteArrayList<ServerTasker> clientsCopy = new CopyOnWriteArrayList<>(onlineClients);

        for (ServerTasker client : clientsCopy) {
            if (client != null && client.currentAccountId != null && client.currentAccountId.equals(accountId) && client != this && client.oos != null) {
                try {
                    // 发送刷新指令给客户端
                    synchronized (client.oos) {
                        client.oos.writeObject("refresh");
                        client.oos.flush();
                    }
                } catch (IOException e) {
                    // 客户端可能已经断开连接
                    System.out.println("通知客户端刷新失败: " + e.getMessage());
                }
            }
        }
    }

    // 获取当前账户ID
    public Long getCurrentAccountId() {
        return currentAccountId;
    }

    // 提供获取登录信息的方法
    public static ConcurrentHashMap<Long, String> getLoginIpMap() {
        return loginIpMap;
    }
}
